/* Trim Function for Strings */
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }

/*
 Call Web Service Extension
 http://wiki.openqa.org/display/SEL/callWebService
 
 (C) Copyright MetaCommunications, Inc. 2007.
     http://www.meta-comm.com
     http://engineering.meta-comm.com

	 20080908 - Added doCallWebServiceForValues and doCallWebServiceForXML - AndrewCheng
	 
Distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND.
*/

Selenium.prototype.doResetWebServiceParameters = function() 
    {
    storedVars["prepare_call_content"] = "";
    };
    
Selenium.prototype.doAddWebServiceParameter = function( name, value ) 
    {
    var enc = function ( s )
        {
        if ( !s.replace )
		{
            s = s.toString();
		}
        return encodeURIComponent( s );
        };
    storedVars["prepare_call_content"] += "&" + name + "=" + enc( value ) ;
    };
	
getWebServiceResponse = function(url)
{
    var get_content = function ()
        {
        var content_obj = storedVars["prepare_call_content"];
        var content = "";
        if ( ! ( !content_obj ) ) 
		{
            content = content_obj.substr( 1 ) + "&";
		}
        // workaround: Safari puts "\0" at the end of the query string
        // This makes this \0 a part of __META_END which we don't need,
        // instead of some used value.
         return content + "__META_END=1";
        };

    var req  = null;
    if (window.XMLHttpRequest) 
        {// branch for native XMLHttpRequest object
        req = new XMLHttpRequest();        
        } 
    else if (window.ActiveXObject) 
        {// branch for IE/Windows ActiveX version
        req = new ActiveXObject("Microsoft.XMLHTTP");
        }    
    if (req) 
        {  
        req.open( "POST", url, false );
        req.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
        req.send( get_content() );

        if ( req.status != 200 )
		{
            throw { status_code: req.status, status_text: req.statusText, response_text: req.responseText };
		}

		return req.responseXML;
		}
	return "";
};

Selenium.prototype.doCallWebService = function( url, varName ) 
    {
    var responseXML = getWebServiceResponse(url);
			
	storedVars[varName] = responseXML.lastChild.childNodes.length > 0 
        ? responseXML.lastChild.childNodes[0].data
        : "";

        LOG.info( 'callWebService: returned [' + storedVars[varName] + ']' );
	};

Selenium.prototype.doCallWebServiceForXML = function( url, varName ) 
    {
    var responseXML = getWebServiceResponse(url);
			
	storedVars[varName] = responseXML;

    LOG.info( 'callWebService: returned [' + storedVars[varName] + ']' )
        
	};

Selenium.prototype.doCallWebServiceForValues = function( url, names ) 
    {
    var array = names.split(',');
	var responseXML = getWebServiceResponse(url);
	
	for (var i = 0; i < array.length; i++)
	{
		var name = array[i].trim();
		storedVars[name] = responseXML.getElementsByTagName(name)[0].firstChild.nodeValue;
	}        
	};


/* Esta es mi extensión a "Call Web Services" para utilizar 
 * los servicios de la W3C */

Selenium.prototype.isValidHTML = function() {
    //Get HTML source
    var source = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' +
        '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> ' +
        '<html xmlns="http://www.w3.org/1999/xhtml"> ' + 
        selenium.getHtmlSource() + 
        ' </html>';
    
    //Add Parameters
    Selenium.prototype.doResetWebServiceParameters();
    Selenium.prototype.doAddWebServiceParameter('fragment', source);
    Selenium.prototype.doAddWebServiceParameter('output', 'soap12'); 
    
    //Make XMLHttpRequest and check validity
    var responseXML = getWebServiceResponse('http://localhost:8000/w3c-markup-validator/check');
    var validity = responseXML.getElementsByTagName('m:validity')[0].firstChild.nodeValue;
    if(validity != 'true') {
        LOG.info('HTML source: ' + source);
        Assert.fail('HTML error count: ' + responseXML.getElementsByTagName('m:errorcount')[0].firstChild.nodeValue );
    }
    else {
        return true;
    }
}


Selenium.prototype.isValidCSS = function() {
    //Get CSS source
    var source = selenium.getBodyText();
    
    //Prepare Call
    var url = 'http://jigsaw.w3.org/css-validator/validator';
    var query_string = '?';
    query_string += "&text=" + encodeURIComponent(source);
    query_string += "&output=soap12";
    query_string += "&profile=css21"; 
    
    //Make XMLHttpRequest and check validity
    req = new XMLHttpRequest();
    req.open("GET", url+query_string, false);
    req.send();
    if ( req.status != 200 ) {
        throw { status_code: req.status, status_text: req.statusText, response_text: req.responseText };
    }
    var validity = req.responseXML.getElementsByTagName('m:validity')[0].firstChild.nodeValue;
    if(validity != 'true') {
        LOG.info( 'CSS source: ' + source );
        Assert.fail('CSS error count: ' + req.responseXML.getElementsByTagName('m:errorcount')[0].firstChild.nodeValue );
    }
    else {
        return true;
    }
}



/* Sideflow extension
 * How to use:  http://51elliot.blogspot.com/2008/02/selenium-ide-goto.html
 *              http://brettweiss.wordpress.com/2009/09/25/perform-while-loop-in-the-selenium-ide/
 * Download:    https://github.com/darrenderidder/sideflow 
 */
 
var gotoLabels= {};
var whileLabels = {};

// overload the original Selenium reset function
Selenium.prototype.reset = function() {
    // reset the labels
    this.initialiseLabels();
    // proceed with original reset code
    this.defaultTimeout = Selenium.DEFAULT_TIMEOUT;
    this.browserbot.selectWindow("null");
    this.browserbot.resetPopups();
}

Selenium.prototype.initialiseLabels = function()
{
    gotoLabels = {};
    whileLabels = { ends: {}, whiles: {} };
    var command_rows = [];
    var numCommands = testCase.commands.length;
    for (var i = 0; i < numCommands; ++i) {
        var x = testCase.commands[i];
        command_rows.push(x);
    }
    var cycles = [];
    for( var i = 0; i < command_rows.length; i++ ) {
        if (command_rows[i].type == 'command')
        switch( command_rows[i].command.toLowerCase() ) {
            case "label":
                gotoLabels[ command_rows[i].target ] = i;
                break;
            case "while":
            case "endwhile":
                cycles.push( [command_rows[i].command.toLowerCase(), i] )
                break;
        }
    }
    var i = 0;
    while( cycles.length ) {
        if( i >= cycles.length ) {
            throw new Error( "non-matching while/endWhile found" );
        }
        switch( cycles[i][0] ) {
            case "while":
                if( ( i+1 < cycles.length ) && ( "endwhile" == cycles[i+1][0] ) ) {
                    // pair found
                    whileLabels.ends[ cycles[i+1][1] ] = cycles[i][1];
                    whileLabels.whiles[ cycles[i][1] ] = cycles[i+1][1];
                    cycles.splice( i, 2 );
                    i = 0;
                } else ++i;
                break;
            case "endwhile":
                ++i;
                break;
        }
    }
}

Selenium.prototype.continueFromRow = function( row_num )
{
    if(row_num == undefined || row_num == null || row_num < 0) {
        throw new Error( "Invalid row_num specified." );
    }
    testCase.debugContext.debugIndex = row_num;
}

// do nothing. simple label
Selenium.prototype.doLabel = function(){};

Selenium.prototype.doGotolabel = function( label )
{
    if( undefined == gotoLabels[label] ) {
        throw new Error( "Specified label '" + label + "' is not found." );
    }
    this.continueFromRow( gotoLabels[ label ] );
};

Selenium.prototype.doGoto = Selenium.prototype.doGotolabel;

Selenium.prototype.doGotoIf = function( condition, label )
{
    if( eval(condition) ) this.doGotolabel( label );
}

Selenium.prototype.doWhile = function( condition )
{
    if( !eval(condition) ) {
        var last_row = testCase.debugContext.debugIndex;
        var end_while_row = whileLabels.whiles[ last_row ];
        if( undefined == end_while_row ) throw new Error( "Corresponding 'endWhile' is not found." );
        this.continueFromRow( end_while_row );
    }
}

Selenium.prototype.doEndWhile = function()
{
    var last_row = testCase.debugContext.debugIndex;
    var while_row = whileLabels.ends[ last_row ] - 1;
    if( undefined == while_row ) throw new Error( "Corresponding 'While' is not found." );
    this.continueFromRow( while_row );
}




/* 
 * Estas son otras funciones que he escrito para hacer
 * más fácil trabajar en Selenium
 */

//Encuentra todos los links dentro del elemento especificado y los devuelve en un arreglo.
Selenium.prototype.getLinksInside = function(locator) {
    var element = this.browserbot.findElement(locator);
    var links = element.getElementsByTagName('a');
    var linksArray = new Array();
    for(var i=0; i < links.length; i++) {
        linksArray.push(links[i].childNodes[0].nodeValue.trim());
    }
    return(linksArray);
}

//Encuentra todos los links que hagan match con pattern, y los devuelve en un arreglo.
Selenium.prototype.getLinksThatMatchHref = function(pattern) {
    var document = selenium.browserbot.getUserWindow().document;
    var links = document.getElementsByTagName('a');
    var linksArray = new Array();
    for(var i=0; i < links.length; i++) {
        if(PatternMatcher.matches(pattern,links[i].childNodes[0].nodeValue)) {
            linksArray.push(links[i].childNodes[0].nodeValue.trim());
        }
    }
    return(linksArray);
}

//Permite encontrar el valor actual (computed style) de cualquier propiedad CSS
Selenium.prototype.doSetElementForAnalysis = function(locator) {
    storedVars['elementForAnalysis'] = this.browserbot.findElement(locator);
}
Selenium.prototype.doClearElementForAnalysis = function(locator) {
    storedVars['elementForAnalysis'] = null;
}
Selenium.prototype.getComputedStyle = function(property) {
    var window = this.browserbot.getUserWindow();
    var result = window.getComputedStyle(storedVars['elementForAnalysis'],null)[property];
    return result;
}

//Override de la función VerifyText() de Selenium
//Si el locator no encuentra al elemento, tira False en vez de error
Selenium.prototype.isText = function(locator, pattern) {
    try {
        return PatternMatcher.matches(pattern, this.getText(locator));
    }
    catch(err) {
        return false;
    }
}
